home *** CD-ROM | disk | FTP | other *** search
/ Aminet 52 / Aminet 52 (2002)(GTI - Schatztruhe)[!][Dec 2002].iso / Aminet / dev / gg / ncurses-5.3.lha / ncurses-5.3 / tack / ansi.c next >
C/C++ Source or Header  |  2002-10-24  |  20KB  |  855 lines

  1. /*
  2. ** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
  3. ** 
  4. ** This file is part of TACK.
  5. ** 
  6. ** TACK is free software; you can redistribute it and/or modify
  7. ** it under the terms of the GNU General Public License as published by
  8. ** the Free Software Foundation; either version 2, or (at your option)
  9. ** any later version.
  10. ** 
  11. ** TACK is distributed in the hope that it will be useful,
  12. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ** GNU General Public License for more details.
  15. ** 
  16. ** You should have received a copy of the GNU General Public License
  17. ** along with TACK; see the file COPYING.  If not, write to
  18. ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19. ** Boston, MA 02111-1307, USA.
  20. */
  21.  
  22. #include <tack.h>
  23.  
  24. MODULE_ID("$Id: ansi.c,v 1.9 2001/06/18 18:44:17 tom Exp $")
  25.  
  26. /*
  27.  * Standalone tests for ANSI terminals.  Three entry points:
  28.  * test_ansi_graphics(), test_ansi_reports() and test_ansi_sgr().
  29.  */
  30.  
  31. /*****************************************************************************
  32.  *
  33.  * Test ANSI status reports
  34.  *
  35.  *****************************************************************************/
  36.  
  37. /* ASCII control characters */
  38. #define A_DC1 0x11        /* Control Q */
  39. #define A_DC3 0x13        /* Control S */
  40. #define A_ESC 0x1b
  41. #define A_DCS 0x90
  42. #define A_CSI 0x9b
  43. #define A_ST  0x9c
  44.  
  45. #define MAX_MODES 256
  46.  
  47. static char default_bank[] = "\033(B\017";
  48. static int private_use, ape, terminal_class;
  49. static short ansi_value[256];
  50. static unsigned char ansi_buf[512], pack_buf[512];
  51.  
  52. struct ansi_reports {
  53.     int lvl, final;
  54.     const char *text;
  55.     const char *request;
  56. };
  57.  
  58. static struct ansi_reports report_list[] = {
  59.     {0, 'c', "(DA) Primary device attributes", "\033[0c"},
  60.     {1, 0, "(DSR) Terminal status", "\033[5n"},
  61.     {1, 'R', "(DSR) Cursor position", "\033[6n"},
  62.     {62, 0, "(DA) Secondary device attributes", "\033[>0c"},
  63.     {62, 0, "(DSR) Printer status", "\033[?15n"},
  64.     {62, 0, "(DSR) Function key definition", "\033[?25n"},
  65.     {62, 0, "(DSR) Keyboard language", "\033[?26n"},
  66.     {63, 0, "(DECRQSS) Data destination", "\033P$q$}\033\\"},
  67.     {63, 0, "(DECRQSS) Status line type", "\033P$q$~\033\\"},
  68.     {63, 0, "(DECRQSS) Erase attribute", "\033P$q\"q\033\\"},
  69.     {63, 0, "(DECRQSS) Personality", "\033P$q\"p\033\\"},
  70.     {63, 0, "(DECRQSS) Top and bottom margins", "\033P$qr\033\\"},
  71.     {63, 0, "(DECRQSS) Character attributes", "\033P$qm\033\\"},
  72.     {63, 0, "(DECRQSS) Illegal request", "\033P$q@\033\\"},
  73.     {63, 0, "(DECRQUPSS) User pref supplemental set", "\033[&u"},
  74.     {63, 0, "(DECRQPSR) Cursor information", "\033[1$w"},
  75.     {63, 0, "(DECRQPSR) Tab stop information", "\033[2$w"},
  76.     {64, 0, "(DA) Tertiary device attributes", "\033[=0c"},
  77.     {64, 0, "(DSR) Extended cursor position", "\033[?6n"},
  78.     {64, 0, "(DSR) Macro space", "\033[?62n"},
  79.     {64, 0, "(DSR) Memory checksum", "\033[?63n"},
  80.     {64, 0, "(DSR) Data integrity", "\033[?75n"},
  81.     {64, 0, "(DSR) Multiple session status", "\033[?85n"},
  82.     {64, 0, "(DECRQSS) Attribute change extent", "\033P$q*x\033\\"},
  83.     {64, 0, "(DECRQSS) Columns per page", "\033P$q$|\033\\"},
  84.     {64, 0, "(DECRQSS) Lines per page", "\033P$qt\033\\"},
  85.     {64, 0, "(DECRQSS) Lines per screen", "\033P$q*|\033\\"},
  86.     {64, 0, "(DECRQSS) Left and right margins", "\033P$qs\033\\"},
  87.     {64, 0, "(DECRQSS) Local functions", "\033P$q+q\033\\"},
  88.     {64, 0, "(DECRQSS) Local function key control", "\033P$q=}\033\\"},
  89.     {64, 0, "(DECRQSS) Select modifier key reporting", "\033P$q+r\033\\"},
  90.     {64, 0, "(DECRQDE) Window report", "\033[\"v"},
  91.     {0, 0, 0, 0}
  92. };
  93.  
  94. struct request_control {
  95.     const char *text;
  96.     const char *expect;
  97.     const char *request;
  98.     const char *set_mode;
  99.     const char *reset_mode;
  100. };
  101.  
  102. /* Request control function selection or setting */
  103. static const struct request_control rqss[] = {
  104.     {"Data sent to screen", "0", "$}", "\033[0$}", 0},
  105.     {"Data sent to disabled status line", "0", "$}", 0, 0},
  106.     {"\033[0$~\033[1$}", "\033[0$}", 0, 0, 0},
  107.     {"Data sent to enabled status line", "1", "$}", 0, 0},
  108.     {"\033[2$~\033[1$}", "\033[0$}", 0, 0, 0},
  109.     {"Disable status line", "0", "$~", "\033[0$~", 0},
  110.     {"Top status line", "1", "$~", "\033[1$~", 0},
  111.     {"Bottom status line", "2", "$~", "\033[2$~", 0},
  112.     {"Erasable character", "0", "\"q", "\033[0\"q", 0},
  113.     {"Nonerasable character", "1", "\"q", "\033[1\"q", "\033[0\"q"},
  114.     {"Top and bottom margins", "3;10", "r", "\0337\033[3;10r", 0},
  115.     {"\033[r\0338", 0, 0, 0, 0},
  116.     {"Top and bottom margins", "default", "r", "\0337\033[r", "\0338"},
  117.     {"Character attributes, dim, bold", "1", "m", "\033[2;1m", "\033[m"},
  118.     {"Character attributes, bold, dim", "2", "m", "\033[1;2m", "\033[m"},
  119.     {"Character attributes, under, rev", "4;7", "m", "\033[4;7m", "\033[m"},
  120.     {"Character attributes, color", "35;42", "m", "\033[35;42m", "\033[m"},
  121.     {"All character attributes", "", "m", "\033[1;2;3;4;5;6;7;8;9m", 0},
  122.     {"\033[m", 0, 0, 0, 0},
  123.     {0, 0, 0, 0, 0}
  124. };
  125.  
  126.  
  127. /*
  128. **    read_ansi()
  129. **
  130. **    read an ANSI status report from terminal
  131. */
  132. static void
  133. read_ansi(void)
  134. {
  135.     int ch, i, j, last_escape;
  136.  
  137.     fflush(stdout);
  138.     read_key((char *)ansi_buf, sizeof(ansi_buf));
  139.     /* Throw away control characters inside CSI sequences.
  140.        Convert two character 7-bit sequences into 8-bit sequences. */
  141.     for (i = j = last_escape = 0; (ch = ansi_buf[i]) != 0; i++) {
  142.         if (ch == A_ESC) {
  143.             if (last_escape == A_ESC) {
  144.                 pack_buf[j++] = A_ESC;
  145.             }
  146.             last_escape = A_ESC;
  147.         } else
  148.         if (last_escape == A_ESC && ch >= '@' && ch <= '_') {
  149.             pack_buf[j++] = last_escape = ch + 0x40;
  150.         } else
  151.         if (last_escape != A_CSI || (ch > 0x20 && ch != 0x80)) {
  152.             if (last_escape == A_ESC) {
  153.                 pack_buf[j++] = A_ESC;
  154.             }
  155.             if (ch > 0x80 && ch < 0xa0) {
  156.                 last_escape = ch;
  157.             }
  158.             pack_buf[j++] = ch;
  159.         }
  160.     }
  161.     if (last_escape == A_ESC) {
  162.         pack_buf[j++] = A_ESC;
  163.     }
  164.     pack_buf[j] = '\0';
  165.     return;
  166. }
  167.  
  168. /*
  169. **    valid_mode(expected)
  170. **
  171. **    read a terminal mode status report and parse the result
  172. **    Return TRUE if we got the expected terminating character.
  173. */
  174. static int
  175. valid_mode(int expected)
  176. {
  177.     unsigned char *s;
  178.     int ch, terminator;
  179.  
  180.     read_ansi();
  181.  
  182.     ape = 0;
  183.     ch = UChar(pack_buf[0]);
  184.     ansi_value[0] = 0;
  185.     if (ch != A_CSI && ch != A_DCS)
  186.         return FALSE;
  187.  
  188.     s = pack_buf + 1;
  189.     private_use = 0;
  190.     if ((*s >= '<') & (*s <= '?')) {
  191.         private_use = *s++;
  192.     }
  193.     terminator = 0;
  194.     for (; (ch = *s); s++) {
  195.         if (ch >= '0' && ch <= '9')
  196.             ansi_value[ape] = ansi_value[ape] * 10 + ch - '0';
  197.         else if (ch == ';' || ch == ':')
  198.             ansi_value[++ape] = 0;
  199.         else if (ch >= '<' && ch <= '?')
  200.             private_use = ch;
  201.         else if (ch >= ' ')
  202.             terminator = (terminator << 8) | ch;
  203.         else
  204.             break;
  205.     }
  206.     return terminator == expected;
  207. }
  208.  
  209. /*
  210. **    read_reports()
  211. **
  212. **    read all the reports in the ANSI report structure
  213. */
  214. static int
  215. read_reports(void)
  216. {
  217.     int i, j, k, tc, vcr, lc;
  218.     char *s;
  219.     const char *t;
  220.  
  221.     lc = 5;
  222.     terminal_class = tc = 0;
  223.     for (i = 0; report_list[i].text; i++, lc++) {
  224.         if (terminal_class < report_list[i].lvl &&
  225.             tc < report_list[i].lvl) {
  226.             put_crlf();
  227.             menu_prompt();
  228.             ptext("/status [q] > ");
  229.             j = wait_here();
  230.             if (j != 'n' && j != 'N')
  231.                 return 0;
  232.             tc = report_list[i].lvl;
  233.             lc = 1;
  234.         } else if (lc + 2 >= lines) {
  235.             put_crlf();
  236.             ptext("Hit any key to continue ");
  237.             (void) wait_here();
  238.             lc = 1;
  239.         }
  240.         sprintf(temp, "%s (%s) ", report_list[i].text,
  241.             expand_command(report_list[i].request));
  242.         ptext(temp);
  243.         for (j = strlen(temp); j < 49; j++)
  244.             putchp(' ');
  245.         tc_putp(report_list[i].request);
  246.         vcr = 0;
  247.         if (report_list[i].final == 0) {
  248.             read_ansi();
  249.         } else if (valid_mode(report_list[i].final))
  250.             switch (report_list[i].final) {
  251.             case 'c':
  252.                 terminal_class = ansi_value[0];
  253.                 break;
  254.             case 'R':
  255.                 vcr = TRUE;
  256.                 break;
  257.             }
  258.         j = UChar(pack_buf[0]);
  259.         if (j != A_CSI && j != A_DCS) {
  260.             put_crlf();
  261.             t = "*** The above request gives illegal response ***";
  262.             ptext(t);
  263.             for (j = strlen(t); j < 49; j++)
  264.                 putchp(' ');
  265.         }
  266.         s = expand((const char *)ansi_buf);
  267.         if (char_count + expand_chars >= columns) {
  268.             put_str("\r\n        ");
  269.             lc++;
  270.         }
  271.         putln(s);
  272.         if (vcr) {    /* find out how big the screen is */
  273.             tc_putp(report_list[i].request);
  274.             if (!valid_mode('R'))
  275.                 continue;
  276.             j = ansi_value[0];
  277.             k = ansi_value[1];
  278.             tc_putp("\033[255B\033[255C\033[6n");
  279.             if (!valid_mode('R'))
  280.                 continue;
  281.             sprintf(temp, "\033[%d;%dH", j, k);
  282.             tc_putp(temp);
  283.             ptext("(DSR) Screen size (CSI 6 n)");
  284.             for (j = char_count; j < 50; j++)
  285.                 putchp(' ');
  286.             sprintf(temp, "%d x %d", ansi_value[1], ansi_value[0]);
  287.             ptextln(temp);
  288.  
  289.         }
  290.     }
  291.     menu_prompt();
  292.     ptext("/status r->repeat test, <return> to continue > ");
  293.     return wait_here();
  294. }
  295.  
  296. /*
  297. **    request_cfss()
  298. **
  299. **    Request Control function selection or settings
  300. */
  301. static int
  302. request_cfss(void)
  303. {
  304.     int i, j, k, l, ch;
  305.     char *s;
  306.  
  307.     put_clear();
  308.     ptextln("Request                         Expected  Received");
  309.     put_crlf();
  310.     for (i = 0; rqss[i].text; i++) {
  311.         ptext(rqss[i].text);
  312.         j = strlen(rqss[i].text) + strlen(rqss[i].expect);
  313.         putchp(' ');
  314.         for (j++; j < 40; j++)
  315.             putchp(' ');
  316.         ptext(rqss[i].expect);
  317.         putchp(' ');
  318.         tc_putp(rqss[i].set_mode);
  319.         sprintf(temp, "\033P$q%s\033\\", rqss[i].request);
  320.         tc_putp(temp);
  321.         read_ansi();
  322.         tc_putp(rqss[i].reset_mode);
  323.         putchp(' ');
  324.         for (j = 0; ansi_buf[j]; j++) {
  325.             if (ansi_buf[j] == 'r') {
  326.                 for (k = j++; (ch = UChar(ansi_buf[k])) != 0; k++)
  327.                     if (ch == A_ESC) {
  328.                         break;
  329.                     } else if (ch == A_ST) {
  330.                         break;
  331.                     }
  332.                 ansi_buf[k] = '\0';
  333.                 s = expand((const char *)&ansi_buf[j]);
  334.                 if (char_count + expand_chars >= columns)
  335.                     put_str("\r\n        ");
  336.                 put_str(s);
  337.             }
  338.         }
  339.         put_crlf();
  340.     }
  341.     /* calculate the valid attributes */
  342.     ptext("Valid attributes:         0");
  343.     j = 0;
  344.     for (i = 1; i < 20; i++) {
  345.         sprintf(temp, "\033[0;%dm\033P$qm\033\\", i);
  346.         tc_putp(temp);
  347.         (void) valid_mode('m');
  348.         if (ape > 0) {
  349.             j = i;
  350.             sprintf(temp, "\033[0m; %d", i);
  351.             tc_putp(temp);
  352.         }
  353.     }
  354.     put_crlf();
  355.     /* calculate how many parameters can be sent */
  356.     ptext("Max number of parameters: ");
  357.     sprintf(temp, "%dm\033P$qm\033\\", j);
  358.     l = -1;
  359.     if (j > 0)
  360.         for (l = 1; l < 33; l++) {
  361.             tc_putp("\033[0");
  362.             for (ch = 1; ch <= l; ch++)
  363.                 put_this(';');
  364.             tc_putp(temp);
  365.             (void) valid_mode('m');
  366.             if (ape == 0)
  367.                 break;
  368.         }
  369.     tc_putp("\033[m");
  370.     if (l >= 0) {
  371.         sprintf(temp, "%d", l);
  372.         ptext(temp);
  373.     } else
  374.         ptext("unknown");
  375.     put_crlf();
  376.     return wait_here();
  377. }
  378.  
  379. /*
  380. **    mode_display(puc, mode, initial, set, reset)
  381. **
  382. **    print the mode display entry
  383. */
  384. static void
  385. mode_display(const char *p, int n, int c, char s, char r)
  386. {
  387.     int k;
  388.  
  389.     sprintf(temp, "%s%d (%c, %c, %c)", p, n, c, s, r);
  390.     k = strlen(temp);
  391.     if (char_count + k >= columns)
  392.         put_crlf();
  393.     for (; k < 14; k++)
  394.         putchp(' ');
  395.     put_str(temp);
  396. }
  397.  
  398. /*
  399. **    terminal_state()
  400. **
  401. **    test DECRQM status reports
  402. */
  403. static void
  404. terminal_state(void)
  405. {
  406.     static const char *puc[] = {"", "<", "=", ">", "?", 0};
  407.  
  408.     int i, j, k, l, modes_found;
  409.     char *s;
  410.     char buf[256], tms[256];
  411.     int mode_puc[MAX_MODES], mode_number[MAX_MODES];
  412.     char set_value[MAX_MODES], reset_value[MAX_MODES];
  413.     char current_value[MAX_MODES];
  414.  
  415.     ptext("Testing terminal mode status. (CSI 0 $ p)");
  416.     tc_putp("\033[0$p");
  417.     modes_found = 0;
  418.     tms[0] = '\0';
  419.     if (valid_mode(('$' << 8) | 'y')) {
  420.         for (i = 0; puc[i]; i++) {
  421.             put_crlf();
  422.             if (i) {
  423.                 sprintf(temp, "Private use: %c", puc[i][0]);
  424.             } else {
  425.                 strcpy(temp, "Standard modes:");
  426.             }
  427.             k = strlen(temp);
  428.             ptext(temp);
  429.             for (j = 0; j < (int) sizeof(buf); buf[j++] = ' ')
  430.                 ;
  431.             for (j = l = 0; j < 255 && j - l < 50; j++) {
  432.                 sprintf(temp, "\033[%s%d$p", puc[i], j);
  433.                 tc_putp(temp);
  434.                 if (!valid_mode(('$' << 8) | 'y')) {
  435.                     /* not valid, save terminating value */
  436.                     s = expand((const char *)ansi_buf);
  437.                     sprintf(tms, "%s%s%d %s  ", tms,
  438.                         puc[i], j, s);
  439.                     break;
  440.                 }
  441.                 if (private_use != puc[i][0])
  442.                     break;
  443.                 if (ansi_value[0] != j)
  444.                     break;
  445.                 if (ansi_value[1]) {
  446.                     l = j;
  447.                     if (k > 70) {
  448.                         buf[k] = '\0';
  449.                         put_crlf();
  450.                         ptextln(buf);
  451.                         for (k = 0; k < (int) sizeof(buf);) {
  452.                             buf[k++] = ' ';
  453.                         }
  454.                         k = 0;
  455.                     }
  456.                     sprintf(temp, " %d", j);
  457.                     ptext(temp);
  458.                     k += strlen(temp);
  459.                     buf[k - 1] = ansi_value[1] + '0';
  460.                     if (modes_found >= MAX_MODES)
  461.                         continue;
  462.                     current_value[modes_found] =
  463.                         ansi_value[1] + '0';
  464.                     /* some modes never return */
  465.                     if ((i == 0 && j == 13)    /* control execution */
  466.                         || (puc[i][0] == '?' && j == 2))    /* VT52 */
  467.                         set_value[modes_found] =
  468.                             reset_value[modes_found] = '-';
  469.                     else
  470.                         set_value[modes_found] =
  471.                             reset_value[modes_found] = ' ';
  472.                     mode_puc[modes_found] = i;
  473.                     mode_number[modes_found++] = j;
  474.                 }
  475.             }
  476.             buf[k] = '\0';
  477.             if (buf[k - 1] != ' ') {
  478.                 put_crlf();
  479.                 ptext(buf);
  480.             }
  481.         }
  482.  
  483.     if ((i = modes_found) != 0) {
  484.         put_crlf();
  485.         put_crlf();
  486.         if (tms[0]) {
  487.             ptextln(tms);
  488.         }
  489.         ptext("Hit 'Y' to test mode set/reset states: ");
  490.         i = wait_here();
  491.     }
  492.     if (i == 'y' || i == 'Y')
  493.         while (1) {
  494. #ifdef STATUSFIX
  495.             FILE *fp;
  496.  
  497. #ifdef TEDANSI
  498.             fp = fopen("ted.ansi", "w");
  499. #else
  500.             fp = fopen("/dev/console", "w");
  501. #endif
  502. #endif
  503.             for (i = j = 0; j < modes_found; j = ++i >> 1) {
  504.                 if (set_value[j] == '-')
  505.                     continue;
  506.                 k = (current_value[j] ^ i) & 1;
  507.                 sprintf(temp, "\033[%s%d%c\033[%s%d$p",
  508.                     puc[mode_puc[j]], mode_number[j],
  509.                     k ? 'l' : 'h',
  510.                     puc[mode_puc[j]], mode_number[j]);
  511. #ifdef STATUSFIX
  512.                 if (fp) {
  513.                     fprintf(fp, "%s\n", expand(temp));
  514.                     fflush(fp);
  515.                 }
  516. #endif
  517.                 tc_putp(temp);
  518.                 if (!valid_mode(('$' << 8) | 'y'))
  519.                     continue;
  520.                 if (k) {
  521.                     reset_value[j] = ansi_value[1] + '0';
  522.                 } else {
  523.                     set_value[j] = ansi_value[1] + '0';
  524.                 }
  525.             }
  526.             put_str("\033[30l");    /* added for GORT bug
  527.                            (WY-185) */
  528. #ifdef STATUSFIX
  529.             if (fp)
  530.                 fclose(fp);
  531. #endif
  532.             tty_set();
  533.             /* print the results */
  534.             put_clear();
  535.             putln("mode (initial, set, reset)");
  536.             for (j = 0; j < modes_found; j++) {
  537.                 mode_display(puc[mode_puc[j]], mode_number[j],
  538.                     current_value[j], set_value[j], reset_value[j]);
  539.             }
  540.             ptext("\n\nHit 'R' to repeat test.  'S' to sort results: ");
  541.             i = wait_here();
  542.             if (i == 's' || i == 'S') {    /* print the same stuff,
  543.                                sorted by
  544.                                current_value */
  545.                 put_crlf();
  546.                 for (i = '1'; i <= '4'; i++) {
  547.                     for (j = 0; j < modes_found; j++) {
  548.                         if (current_value[j] == i)
  549.                             mode_display(puc[mode_puc[j]],
  550.                                 mode_number[j], current_value[j],
  551.                                 set_value[j], reset_value[j]);
  552.                     }
  553.                 }
  554.                 ptext("\n\nHit 'R' to repeat test: ");
  555.                 i = wait_here();
  556.             }
  557.             if (i != 'r' && i != 'R')
  558.                 break;
  559.             tty_raw(1, char_mask);
  560.         }
  561.     } else {
  562.         tty_set();
  563.     }
  564. }
  565.  
  566.  
  567. /*
  568. **    ansi_report_help()
  569. **
  570. **    Display the informational data for the ANSI report test.
  571. */
  572. static void
  573. ansi_report_help(void)
  574. {
  575.     ptext("Begin ANSI status report testing. ");
  576.     ptext(" Parity bit set will be displayed in reverse video. ");
  577.     ptext(" If the terminal hangs, hit any alphabetic key. ");
  578.     ptextln(" Use n to continue testing.  Use q to quit.");
  579.     put_crlf();
  580. }
  581.  
  582. /*
  583. **    test_ansi_reports()
  584. **
  585. **    Test the ANSI status report functions
  586. */
  587. void
  588. tools_status(
  589.     struct test_list *t GCC_UNUSED,
  590.     int *state GCC_UNUSED,
  591.     int *ch)
  592. {
  593.     int i;
  594.  
  595.     put_clear();
  596.     ansi_report_help();
  597.     tty_raw(1, char_mask);
  598.  
  599.     do {
  600.         i = read_reports();
  601.         if (i != 'r' && i != 'R') {
  602.             *ch = i;
  603.             return;
  604.         }
  605.     } while (i);
  606.  
  607.     if (terminal_class >= 63) {
  608.         do {
  609.             i = request_cfss();
  610.         } while (i == 'r' || i == 'R');
  611.         *ch = i;
  612.         terminal_state();
  613.     } else {
  614.         tty_set();
  615.     }
  616. }
  617.  
  618.  
  619. /*
  620. **    display_sgr()
  621. **
  622. **    Test a range of ANSI sgr attributes
  623. **    puc -> Private Use Character
  624. */
  625. static void 
  626. display_sgr(int puc)
  627. {
  628.     int k;
  629.  
  630.     temp[0] = puc;
  631.     temp[1] = '\0';
  632.     for (k = 0; k < 80; k++) {
  633.         if (char_count + 8 > 80)
  634.             put_crlf();
  635.         else if (char_count + 8 > columns)
  636.             put_crlf();
  637.         else if (k > 0)
  638.             printf(" ");
  639.         printf("\033[%s%dmMode %2d\033[0m", temp, k, k);
  640.         char_count += 8;
  641.         if (puc == '\0') {
  642.             if (k == 19)
  643.                 printf("\033[10m");
  644.             if (k == 39)
  645.                 printf("\033[37m");
  646.             if (k == 49)
  647.                 printf("\033[40m");
  648.         }
  649.     }
  650.     put_crlf();
  651.     if (puc == '<')
  652.         printf("\033[<1m");
  653.     else if (puc)
  654.         printf("\033[%s0m", temp);
  655.     set_attr(0);
  656. }
  657.  
  658. /*
  659. **    print_sgr20(on, off)
  660. **
  661. **    print the sgr line for sgr20()
  662. */
  663. static void 
  664. print_sgr20(int on, int off)
  665. {
  666.     if (char_count > columns - 13) {
  667.         put_crlf();
  668.     } else if (char_count) {
  669.         put_str("  ");
  670.     }
  671.     char_count += 11;
  672.     printf("%d/%d \033[%dmon\033[%dm off\033[0m", on, off, on, off);
  673. }
  674.  
  675. /*
  676. **    sgr20(void)
  677. **
  678. **    display the enter/exit attributes 1-9 and 20-29
  679. */
  680. static void 
  681. sgr20(void)
  682. {
  683.     int k;
  684.  
  685.     put_crlf();
  686.     ptextln("Test enter/exit attributes 1-9 and 21-29.");
  687.     for (k = 1; k < 10; k++) {
  688.         print_sgr20(k, k + 20);
  689.     }
  690.     print_sgr20(1, 22);    /* bold */
  691.     print_sgr20(2, 22);    /* dim */
  692.     print_sgr20(8, 22);    /* blank */
  693.     printf("\033[0m");
  694.     set_attr(0);
  695. }
  696.  
  697. /*
  698. **    tools_sgr(testlist, state, ch)
  699. **
  700. **    Run the ANSI graphics rendition mode tool
  701. **    Return the last character typed.
  702. */
  703. void
  704. tools_sgr(
  705.     struct test_list *t GCC_UNUSED,
  706.     int *state GCC_UNUSED,
  707.     int *ch)
  708. {
  709.     int k;
  710.  
  711.     put_clear();
  712.     for (k = 0;;) {
  713.         display_sgr(k);
  714.         put_crlf();
  715.         menu_prompt();
  716.         ptext("/sgr Enter =><?r [<cr>] > ");
  717.         k = wait_here();
  718.         if ((k == 'r') || (k == 'R')) {
  719.             k = 0;
  720.         } else if ((k < '<') || (k > '?')) {
  721.             break;
  722.         }
  723.     }
  724.     sgr20();
  725.  
  726.     put_newlines(2);
  727.     *ch = REQUEST_PROMPT;
  728. }
  729.  
  730. /*****************************************************************************
  731.  *
  732.  * Test ANSI graphics
  733.  *
  734.  *****************************************************************************/
  735. /*
  736. **    select_bank(bank)
  737. **
  738. **    select a graphics character set for ANSI terminals
  739. */
  740. static void
  741. select_bank(char *bank)
  742. {
  743.     tc_putp(bank);
  744.     switch (bank[1] & 3) {
  745.     case 0:
  746.         putchp('O' & 0x1f);    /* control O */
  747.         break;
  748.     case 1:
  749.         putchp('N' & 0x1f);    /* control N */
  750.         tc_putp("\033~");
  751.         break;
  752.     case 2:
  753.         tc_putp("\033n\033}");
  754.         break;
  755.     case 3:
  756.         tc_putp("\033o\033|");
  757.         break;
  758.     }
  759. }
  760.  
  761. /*
  762. **    show_characters(bank, bias)
  763. **
  764. **    print the ANSI graphics characters
  765. */
  766. static void
  767. show_characters(char *bank, int bias)
  768. {
  769.     int i;
  770.  
  771.     sprintf(temp, "G%d GL   ", bank[1] & 3);
  772.     ptext(temp);
  773.     select_bank(bank);
  774.     for (i = ' '; i < 0x80; i++) {
  775.         if (char_count >= columns ||
  776.             (i != ' ' && (i & 31) == 0))
  777.             put_str("\n        ");
  778.         putchp(i + bias);
  779.     }
  780.     select_bank(default_bank);
  781.     put_str("   DEL <");
  782.     select_bank(bank);
  783.     putchp(0x7f + bias);
  784.     select_bank(default_bank);
  785.     putchp('>');
  786.     put_crlf();
  787.     put_crlf();
  788. }
  789.  
  790.  
  791. /* ANSI graphics test
  792.         94     96   character sets
  793.    G0   (      ,
  794.    G1   )      -
  795.    G2   *      .
  796.    G3   +      /
  797.  
  798. Standard Definitions
  799.    A    UK
  800.    B    US ASCII
  801.  
  802. Dec extended definitions
  803.    0    Special graphics
  804.  
  805.  */
  806.  
  807. /*
  808. **    tools_charset(testlist, state, ch)
  809. **
  810. **    Run the ANSI alt-charset mode tool
  811. */
  812. void
  813. tools_charset(
  814.     struct test_list *t GCC_UNUSED,
  815.     int *state GCC_UNUSED,
  816.     int *chp GCC_UNUSED)
  817. {
  818.     int j, ch;
  819.     char bank[32];
  820.  
  821.     put_clear();
  822.     ptext("Enter the bank ()*+,-./ followed by the character set");
  823.     ptext(" 0123456789:;<=>? for private use, and");
  824.     ptextln(" @A...Z[\\]^_`a...z{|}~ for standard sets.");
  825.     strcpy(bank, "\033)0");
  826.     for (; bank[0];) {
  827.         put_crlf();
  828.         show_characters(bank, 0);
  829.  
  830.         /* G0 will not print in GR */
  831.         if (bank[1] & 3) {
  832.             show_characters(bank, 0x80);
  833.         }
  834.         ptext("bank+set> ");
  835.         for (j = 1; (ch = getchp(char_mask)); j++) {
  836.             if (ch == EOF)
  837.                 break;
  838.             putchp(ch);
  839.             if (j == 1 && ch > '/')
  840.                 j++;
  841.             bank[j] = ch;
  842.             if (ch < ' ' || ch > '/')
  843.                 break;
  844.             if (j + 1 >= (int) sizeof(bank))
  845.                 break;
  846.         }
  847.         if (j == 1)
  848.             break;
  849.         if (bank[j] < '0' || bank[j] > '~')
  850.             break;
  851.         bank[j + 1] = '\0';
  852.     }
  853.     put_crlf();
  854. }
  855.